﻿var Prototype =
{
    Browser: (function ()
    {
        var ua = navigator.userAgent;
        var isOpera = Object.prototype.toString.call(window.opera) == '[object Opera]';
        return {
            IE: !!window.attachEvent && !isOpera,
            Opera: isOpera,
            WebKit: ua.indexOf('AppleWebKit/') > -1,
            Gecko: ua.indexOf('Gecko') > -1 && ua.indexOf('KHTML') === -1,
            MobileSafari: /Apple.*Mobile/.test(ua)
        }
    })(),

    BrowserFeatures: {
        XPath: !!document.evaluate,
        SelectorsAPI: !!document.querySelector,
        ElementExtensions: (function ()
        {
            var constructor = window.Element || window.HTMLElement;
            return !!(constructor && constructor.prototype);
        })(),
        SpecificElementExtensions: (function ()
        {
            // First, try the named class
            if (typeof window.HTMLDivElement !== 'undefined')
                return true;

            var div = document.createElement('div'),
          form = document.createElement('form'),
          isSupported = false;

            if (div['__proto__'] && (div['__proto__'] !== form['__proto__']))
            {
                isSupported = true;
            }

            div = form = null;

            return isSupported;
        })()
    },

    ScriptFragment: '<script[^>]*>([\\S\\s]*?)<\/script>',
    JSONFilter: /^\/\*-secure-([\s\S]*)\*\/\s*$/,
    emptyFunction: function () { },
    K: function (x) { return x }
};

if (Prototype.Browser.MobileSafari)
    Prototype.BrowserFeatures.SpecificElementExtensions = false;

//= require "lang"
//= require "ajax"
//= require "dom"

//= require "deprecated"

var Enumerable = (function ()
{
    function each(iterator, context)
    {
        var index = 0;
        try
        {
            this._each(function (value)
            {
                iterator.call(context, value, index++);
            });
        } catch (e)
        {
            if (e != $break) throw e;
        }
        return this;
    }

    function eachSlice(number, iterator, context)
    {
        var index = -number, slices = [], array = this.toArray();
        if (number < 1) return array;
        while ((index += number) < array.length)
            slices.push(array.slice(index, index + number));
        return slices.collect(iterator, context);
    }

    function all(iterator, context)
    {
        iterator = iterator || Prototype.K;
        var result = true;
        this.each(function (value, index)
        {
            result = result && !!iterator.call(context, value, index);
            if (!result) throw $break;
        });
        return result;
    }

    function any(iterator, context)
    {
        iterator = iterator || Prototype.K;
        var result = false;
        this.each(function (value, index)
        {
            if (result = !!iterator.call(context, value, index))
                throw $break;
        });
        return result;
    }

    function collect(iterator, context)
    {
        iterator = iterator || Prototype.K;
        var results = [];
        this.each(function (value, index)
        {
            results.push(iterator.call(context, value, index));
        });
        return results;
    }

    function detect(iterator, context)
    {
        var result;
        this.each(function (value, index)
        {
            if (iterator.call(context, value, index))
            {
                result = value;
                throw $break;
            }
        });
        return result;
    }

    function findAll(iterator, context)
    {
        var results = [];
        this.each(function (value, index)
        {
            if (iterator.call(context, value, index))
                results.push(value);
        });
        return results;
    }

    function grep(filter, iterator, context)
    {
        iterator = iterator || Prototype.K;
        var results = [];

        if (Object.isString(filter))
            filter = new RegExp(RegExp.escape(filter));

        this.each(function (value, index)
        {
            if (filter.match(value))
                results.push(iterator.call(context, value, index));
        });
        return results;
    }

    function include(object)
    {
        if (Object.isFunction(this.indexOf))
            if (this.indexOf(object) != -1) return true;

        var found = false;
        this.each(function (value)
        {
            if (value == object)
            {
                found = true;
                throw $break;
            }
        });
        return found;
    }

    function inGroupsOf(number, fillWith)
    {
        fillWith = Object.isUndefined(fillWith) ? null : fillWith;
        return this.eachSlice(number, function (slice)
        {
            while (slice.length < number) slice.push(fillWith);
            return slice;
        });
    }

    function inject(memo, iterator, context)
    {
        this.each(function (value, index)
        {
            memo = iterator.call(context, memo, value, index);
        });
        return memo;
    }

    function invoke(method)
    {
        var args = $A(arguments).slice(1);
        return this.map(function (value)
        {
            return value[method].apply(value, args);
        });
    }

    function max(iterator, context)
    {
        iterator = iterator || Prototype.K;
        var result;
        this.each(function (value, index)
        {
            value = iterator.call(context, value, index);
            if (result == null || value >= result)
                result = value;
        });
        return result;
    }

    function min(iterator, context)
    {
        iterator = iterator || Prototype.K;
        var result;
        this.each(function (value, index)
        {
            value = iterator.call(context, value, index);
            if (result == null || value < result)
                result = value;
        });
        return result;
    }

    function partition(iterator, context)
    {
        iterator = iterator || Prototype.K;
        var trues = [], falses = [];
        this.each(function (value, index)
        {
            (iterator.call(context, value, index) ?
        trues : falses).push(value);
        });
        return [trues, falses];
    }

    function pluck(property)
    {
        var results = [];
        this.each(function (value)
        {
            results.push(value[property]);
        });
        return results;
    }

    function reject(iterator, context)
    {
        var results = [];
        this.each(function (value, index)
        {
            if (!iterator.call(context, value, index))
                results.push(value);
        });
        return results;
    }

    function sortBy(iterator, context)
    {
        return this.map(function (value, index)
        {
            return {
                value: value,
                criteria: iterator.call(context, value, index)
            };
        }).sort(function (left, right)
        {
            var a = left.criteria, b = right.criteria;
            return a < b ? -1 : a > b ? 1 : 0;
        }).pluck('value');
    }

    function toArray()
    {
        return this.map();
    }

    function zip()
    {
        var iterator = Prototype.K, args = $A(arguments);
        if (Object.isFunction(args.last()))
            iterator = args.pop();

        var collections = [this].concat(args).map($A);
        return this.map(function (value, index)
        {
            return iterator(collections.pluck(index));
        });
    }

    function size()
    {
        return this.toArray().length;
    }

    function inspect()
    {
        return '#<Enumerable:' + this.toArray().inspect() + '>';
    }

    return {
        each: each,
        eachSlice: eachSlice,
        all: all,
        every: all,
        any: any,
        some: any,
        collect: collect,
        map: collect,
        detect: detect,
        findAll: findAll,
        select: findAll,
        filter: findAll,
        grep: grep,
        include: include,
        member: include,
        inGroupsOf: inGroupsOf,
        inject: inject,
        invoke: invoke,
        max: max,
        min: min,
        partition: partition,
        pluck: pluck,
        reject: reject,
        sortBy: sortBy,
        toArray: toArray,
        entries: toArray,
        zip: zip,
        size: size,
        inspect: inspect,
        find: detect
    };
})();

(function ($)
{
    /*
    String extend
    */
    $.extend(String.prototype,
    {
        trim: function () { return $.trim(this); },
        isEmptyOrWhiteSpace: function () { return $.trim(this) == ''; },
        startWith: function (pattern) { return this.lastIndexOf(pattern, 0) === 0; },
        endWith: function (pattern)
        {
            var d = this.length - pattern.length;
            return d >= 0 && this.indexOf(pattern, d) === d;
        },
        escapeHTML: function () { return this.replace(/&/g, '&amp;').replace(/</g, '&lt;').replace(/>/g, '&gt;'); },
        unescapeHTML: function () { return this.stripTags().replace(/&lt;/g, '<').replace(/&gt;/g, '>').replace(/&amp;/g, '&'); },
        parseJSON: function () { return $.parseJSON('' + this); },
        parseXML: function () { return $.parseXML(this); },
        contains: function (pattern) { return this.indexOf(pattern) > -1; },
        isJSON: function ()
        {
            var str = this;
            if (str.isEmptyOrWhiteSpace()) return false;
            str = str.replace(/\\(?:["\\\/bfnrt]|u[0-9a-fA-F]{4})/g, '@');
            str = str.replace(/"[^"\\\n\r]*"|true|false|null|-?\d+(?:\.\d*)?(?:[eE][+\-]?\d+)?/g, ']');
            str = str.replace(/(?:^|:|,)(?:\s*\[)+/g, '');
            return (/^[\],:{}\s]*$/).test(str);
        },
        stripTags: function () { return this.replace(/<\w+(\s+("[^"]*"|'[^']*'|[^>])+)?>|<\/\w+>/gi, ''); },
        toArray: function () { return this.split(''); },
        toInt: function () { return parseInt(this); },
        toFloat: function () { return parseFloat(this); },
        capitalize: function ()
        {
            var a = [];
            $.each(this.split(' '), function (i, n)
            {
                a.push(n.charAt(0).toUpperCase() + n.substring(1).toLowerCase());
            })
            return a.join(' ');
        },
        times: function (count) { return count < 1 ? '' : new Array(count + 1).join(this); }
    });

    /*
    Number extend
    */

    $.extend(Number.prototype,
    {
        abs: function () { return Math.abs(this); },
        round: function () { return Math.round(this); },
        ceil: function () { return Math.ceil(this); },
        floor: function () { return Math.floor(this); },
        toPaddedString: function (length, radix)
        {
            var string = this.toString(radix || 10);
            return '0'.times(length - string.length) + string;
        }
    });

    /*
    Math extend
    */
    $.extend(Math.prototype,
    {
        random: function (min, max) { }
    });


    /*
    Object extend
    */

    $.extend(Object.prototype,
    {
        isString: function () { return toString.call(this) === "[object String]"; },
        isFunction: function () { return typeof (this) === "function" },
        isNumber: function () { return toString.call(this) === "[object Number]"; },
        isArray: function () { return toString.call(this) === "[object Array]"; },
        isDate: function () { return toString.call(this) === "[object Date]"; },
        isBoolean: function () { return toString.call(this) === "[object Boolean]"; }
    });

    /*
    Array extend
    */
    $.extend(Array.prototype, Enumerable);
    $.extend(Array.prototype,
        {
            clear: function ()
            {
                this.length = 0;
                return this;
            },
            clone: function () { return this.slice(0); },
            //        compact: function () { return this.select(function (value) { return value != null; }) },
            first: function () { return this[0]; },
            flatten: function ()
            {
                return this.inject([], function (array, value)
                {
                    if (Object.isArray(value))
                        return array.concat(value.flatten());
                    array.push(value);
                    return array;
                });
            },
            indexOf: function (item, i)
            {
                i || (i = 0);
                var length = this.length;
                if (i < 0) i = length + i;
                for (; i < length; i++)
                    if (this[i] === item) return i;
                return -1;
            },
            inspect: function () { return '[' + this.map(Object.inspect).join(', ') + ']'; },
            intersect: function (array)
            {
                return this.uniq().findAll(function (item)
                {
                    return array.detect(function (value) { return item === value });
                });
            },
            last: function () { return this[this.length - 1]; },
            lastIndexOf: function (item, i)
            {
                i = isNaN(i) ? this.length : (i < 0 ? this.length + i : i) + 1;
                var n = this.slice(0, i).reverse().indexOf(item);
                return (n < 0) ? n : i - n - 1;
            },
            reverse: function (inline)
            {
                return (inline === false ? this.toArray() : this)._reverse();
            },
            uniq: function (sorted)
            {
                return this.inject([], function (array, value, index)
                {
                    if (0 == index || (sorted ? array.last() != value : !array.include(value)))
                        array.push(value);
                    return array;
                });
            },
            without: function ()
            {
                var values = slice.call(arguments, 0);
                return this.select(function (value)
                {
                    return !values.include(value);
                });
            }

        });

    /*
    Date extend
    */

    $.extend(Date.prototype,
    {
        toJSON: function ()
        {
            return this.getUTCFullYear() + '-' +
                  (this.getUTCMonth() + 1).toPaddedString(2) + '-' +
                  this.getUTCDate().toPaddedString(2) + 'T' +
                  this.getUTCHours().toPaddedString(2) + ':' +
                  this.getUTCMinutes().toPaddedString(2) + ':' +
                  this.getUTCSeconds().toPaddedString(2) + 'Z';
        },
        toISOString: function () { return this.toJSON(); }
    });
})(jQuery);